﻿using Kinlo.Entitys;
using Kinlo.MESDocking;
using Microsoft.VisualBasic;
using SixLabors.ImageSharp.Metadata.Profiles.Iptc;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UIWindows.Domains;
using UIWindows.GlobalStatics;
using UIWindows.Services.Context;
using UIWindows.Tools.Helper;
using XingLucifer.IBase;
using XingLucifer.IBase.Enums;
using XingLucifer.IBase.Models.PLCInteraktion;

namespace UIWindows.Services
{
    public abstract class ServierBase
    {

        protected DeviceConfigStatic _deviceConfig;
        protected SystemConfigStatic _systemConfig;
        protected UserConfigStatic _userConfig;
        protected ParameterStatic _parameterStatic;
        protected TemporaryStatic _temporaryStatic;
        protected HomeStatic _homeStatic;

        public ServierBase(DeviceConfigStatic deviceConfig, SystemConfigStatic systemConfig,
            UserConfigStatic userConfig, ParameterStatic parameterStatic, 
            TemporaryStatic temporaryStatic, HomeStatic homeStatic)
        {
            _deviceConfig = deviceConfig;
            _systemConfig = systemConfig;
            _userConfig = userConfig;
            _parameterStatic = parameterStatic;
            _temporaryStatic = temporaryStatic;
            _homeStatic = homeStatic;
        }

        protected Context.DataContext _context;
        public virtual Task Handle(Context.DataContext context)
        {
            int count = 0;
            var plc = _deviceConfig.DeviceList.FirstOrDefault(x => x.ServiceName == context.ServiceName && x.TaskType == TaskTypes.扫描信号);
            if (plc != null)
            {
                while (count < 3)
                {
                    if (plc.Communication.WriteSingle((ushort)2, context.Address_Signal, 0, 0))
                    {
                        RunLog("启动地址 置2 成功", MessageLevelType.信息);
                        break;
                    }
                    else
                    {
                        RunLog("启动地址 置2 失败", MessageLevelType.警告);
                    }
                    count++;
                }
            }
            TaskService.Instance.RemoveTask(context);
            RunLog("结束任务", MessageLevelType.信息);
            return Task.CompletedTask;
        }

        protected bool ClearSignal(Context.DataContext context)
        {
            if (_context == null)
            {
                _context = context;
            }
            RunLog($"-[{context.Address_Signal}] 收到PLC信号", MessageLevelType.信息);
            var plc = _deviceConfig.DeviceList.FirstOrDefault(x => x.ServiceName == context.ServiceName && x.TaskType == TaskTypes.扫描信号);
            if (plc != null)
            {
                if (plc.Communication.WriteSingle((ushort)99, context.Address_Signal, 0, 0))
                {
                    RunLog($"-[{context.Address_Signal}] 启动地址 置99 成功", MessageLevelType.信息);
                    return true;
                }
                else
                {
                    RunLog($"-[{context.Address_Signal}] 启动地址 置99 失败", MessageLevelType.警告);
                }
            }
            Thread.Sleep(500);
            return false;
        }

        protected void RunLog(string info, MessageLevelType levelType = MessageLevelType.信息, Context.DataContext context = default)
        {
            if (context != null)
            {
                _context = context;
            }
            if (_context == null)
            {
                return;
            }
            $"[{_context.ServiceName}]-[{_context.TaskType}]-[{_context.DeviceType}]{info}".RunLog(levelType);
        }

        /// <summary>
        /// 扫码枪通用扫码方法
        /// </summary>
        /// <param name="scancode_count">重复扫码次数</param>
        /// <param name="devices">扫码枪设备</param>
        /// <param name="index">设备序号</param>
        /// <returns></returns>
        public string ScanCode(int scancode_count, IDevices devices, int index, bool isBattery = true)
        {
            for (int i = 0; i < scancode_count; i++)
            {
                string? barcode = devices.ReadSingle<string>(0, 26);
                RunLog($"-[{index}] 扫码枪返回：{barcode}");
                barcode = System.Text.RegularExpressions.Regex.Match(barcode, isBattery ? _systemConfig.SCM.BarcodeRules : _systemConfig.SCM.CupCodeRules, System.Text.RegularExpressions.RegexOptions.Compiled).Value;
                RunLog($"-[{index}] 校验后：{barcode}");
                if (!string.IsNullOrEmpty(barcode))
                {
                    return barcode;
                }
                Thread.Sleep(_parameterStatic.RunParameter.IntervalTime_ScanCode);
            }
            return string.Empty;
        }

        /// <summary>
        /// 写入结果
        /// </summary>
        /// <param name="resultTypes">结果</param>
        /// <param name="devices">设备链接</param>
        /// <param name="address">地址</param>
        /// <param name="context">上下文</param>
        public void WriteResult(ResultTypes resultTypes, IDevices devices, int address, Context.DataContext context, string barcode = default)
        {
            ushort ng_type = 0;
            switch (resultTypes)
            {
                case ResultTypes.合格: ng_type = 1; break;
                default:
                case ResultTypes.注液量发送失败:
                case ResultTypes.扫码失败:
                case ResultTypes.短路NG:
                case ResultTypes.测高NG:
                case ResultTypes.不合格:
                case ResultTypes.扫码NG: ng_type = 2; break;
                case ResultTypes.注液量不匹配:
                case ResultTypes.MES_NG:
                case ResultTypes.记忆跟踪NG: ng_type = 3; break;
                case ResultTypes.称重偏轻:
                case ResultTypes.称重偏重:
                case ResultTypes.注液量偏多: ng_type = 4; break;
                case ResultTypes.注液量偏少: ng_type = 5; break;
            }
            for (int i = 0; i < 3; i++)
            {
                address = address + (context.AddressingMethod == "字节" ? 8 : 4);
                if (devices.WriteSingle(ng_type, address, 0, 0))
                {
                    RunLog($"-[{barcode}] 第[{i}]次 结果 [{resultTypes}] 写入成功 地址：{address} 结果：{ng_type}", MessageLevelType.信息);
                    return;
                }
                else
                {
                    RunLog($"-[{barcode}] 第[{i}]次 结果 [{resultTypes}] 写入失败", MessageLevelType.警告);
                }
            }
        }

        protected bool WriteInjectionVolume(float value_inj, IDevices devices, int address, DataContext context, string barcode)
        {
            for (int i = 1; i < 4; i++)
            {
                if (devices.WriteSingle(value_inj, address + (context.AddressingMethod == "字节" ? 12 : 6), 0, 0))
                {
                    RunLog($"-[{barcode}] 第[{i}]次 注液量 [{value_inj:F2}] 写入成功", MessageLevelType.信息);
                    return true;
                }
                else
                {
                    RunLog($"-[{barcode}] 第[{i}]次 注液量 [{value_inj:F2}] 写入失败", MessageLevelType.警告);
                }
            }
            return false;
        }

        /// <summary>.
        /// 写入指令
        /// </summary>
        /// <param name="value">值</param>
        /// <param name="devices">PLC链接</param>
        /// <param name="address">地址</param>
        public bool WriteCMD(ushort value, IDevices devices, int address)
        {
            for (int i = 0; i < 3; i++)
            {
                if (devices.WriteSingle(value, address, 0, 0))
                {
                    RunLog($"第[{i}]次 命令 [{value}] 写入成功", MessageLevelType.信息);
                    return true;
                }
                else
                {
                    RunLog($"第[{i}]次 命令 [{value}] 写入失败", MessageLevelType.警告);
                }
            }
            return false;
        }

        /// <summary>
        /// 读取记忆
        /// </summary>
        /// <param name="devices">链接设备</param>
        /// <param name="address_struct">结构体起始地址</param>
        /// <param name="struct_length">结构体长度</param>
        /// <param name="alarm_address">报警地址</param>
        /// <returns></returns>
        public (bool, List<BatteryDataModel>) ReadErinnerungen(IDevices devices, int address_struct, int struct_length, int alarm_address, string method)
        {
            try
            {
                BatteryArrayModel batteryArray = new BatteryArrayModel(struct_length);
                List<BatteryDataModel> batteryDatas = new List<BatteryDataModel>();
                for (int i = 0; i < 3; i++)
                {
                    try
                    {
                        var data_obj = devices.ReadClass(address_struct, batteryArray);
                        if (data_obj == null)
                        {
                            RunLog($"读取记忆异常！！！");
                            return new(false, batteryDatas); ;
                        }
                        for (int j = 0; j < batteryArray.Batterys.Length; j++)
                        {
                            if (batteryArray.Batterys[j].ID != 0)
                            {
                                batteryDatas.Add(new BatteryDataModel()
                                {
                                    Index = (byte)(j + 1),
                                    Address_Struct = address_struct + ((method == "字节" ? 20 : 10) * j),
                                    SnowflakeId = batteryArray.Batterys[j].ID,
                                    Data_PLC = batteryArray.Batterys[j].Data_PLC,
                                    Result_PLC = batteryArray.Batterys[j].Results_PLC,
                                });
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        RunLog($"[异常]读取记忆：{ex}");
                    }
                    if (batteryDatas.Count > 0)
                    {
                        return new(false, batteryDatas);
                    }
                    if (i == 2 && batteryDatas.Count == 0)
                    {
                        WriteCMD(1, devices, alarm_address);
                    }
                    Thread.Sleep(500);
                }
            }
            catch (Exception ex)
            {
                RunLog($"读取记忆异常：{ex}");
            }
            return new(true, default);
        }

        public double? GetWeiging(Models.Devices.DeviceClientModel device, string barcode = default)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Restart();
            double? before_weighing = null, after_weighing = null;
            while (stopwatch.ElapsedMilliseconds < _systemConfig.SCM.WeighingTimeout)
            {
                before_weighing = device.Communication.ReadSingle<double>(0, 0);
                if (before_weighing != null)
                {
                    RunLog($"-[{device.Index}] [{barcode}] 获取到重量 ==> {before_weighing} g");
                    if (after_weighing != null)
                    {
                        double difference = Math.Round((double)(before_weighing - after_weighing), 1, MidpointRounding.AwayFromZero);
                        if (difference >= -0.3 && difference <= 0.3)
                        {
                            RunLog($"-[{device.Index}] [{barcode}] 获取到的稳定值 ==> {before_weighing} g");
                            stopwatch.Stop();
                            return before_weighing;
                        }
                    }
                    after_weighing = before_weighing;
                }
                Thread.Sleep(500);
            }
            stopwatch.Stop();
            return default;
        }

        /// <summary>
        /// 写入浮点型
        /// </summary>
        /// <param name="value">数值</param>
        /// <param name="devices">设备接口</param>
        /// <param name="address">写入地址</param>
        public void WriteFloat(double value, IDevices devices, int address)
        {
            for (int i = 0; i < 3; i++)
            {
                if (devices.WriteSingle((float)value, address, 0, 0))
                {
                    RunLog($"第[{i}]次 命令 [{value}] 写入成功", MessageLevelType.信息);
                    return;
                }
                else
                {
                    RunLog($"第[{i}]次 命令 [{value}] 写入失败", MessageLevelType.警告);
                }
            }
        }


    }
}
